package com.uuticketweb.ticket.flight.action;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.uuticket.processor.Processor;
import com.uuticket.processor.ProcessorFactory;
import com.uuticketweb.ticket.flight.bean.FlightInfo;
import com.uuticketweb.ticket.flight.bean.FlightWithPrice;
import com.uuticketweb.ticket.flight.service.FlightService;
import com.uuticketweb.ticket.flight.service.factory.FlightServiceFactory;
import com.uuticketweb.ticket.pojos.CompanyTurncity;
import com.uuticketweb.ticket.pojos.PlaneInfo;
import com.uuticketweb.ticket.pojos.TwoCode;
import com.uuticketweb.ticket.util.DateHelper;
import com.uuticketweb.ticket.util.MyUtils;

public class FlightQueryAction extends ActionSupport {
	
	private static final Log logger = LogFactory.getLog(FlightQueryAction.class);
	
	private String departure;
	private String destination;
	private String queryCityAirport;
	private String itineryType;
	private String toDate;
	private String backDate;
	private String bunk;
	private String carrier;
	private String turncity;
	private String passengersNum;
	
	public String execute() {
		return "";
	}
	
	public String show() throws Exception {
		
		FlightService flightService = FlightServiceFactory.getFlightService();
		List twoCodeList = flightService.getTwoCode();
		twoCodeList.add(0, new TwoCode(TwoCode.ALL_TWO_CODE, "ALL", "", "", ""));
		ActionContext.getContext().put("twoCodeList", twoCodeList);
		List turncityList = flightService.getDistinctTurncityThreecode();
		ActionContext.getContext().put("turncityList", turncityList);
		return "query";
	}
	
	public String getContinent() throws Exception {
		FlightService flightService = FlightServiceFactory.getFlightService();
		List continentList = flightService.getAllContinent();
		ActionContext.getContext().put("continentList", continentList);
		return "getContinent";
	}
	
	public String getCountry() throws Exception {
		FlightService flightService = FlightServiceFactory.getFlightService();
		String continent = MyUtils.getUrlDecodedRequestParameter(ServletActionContext.getRequest(), "continent", "utf-8");
		List countryList = flightService.getCountryOfContinent(continent);
		ActionContext.getContext().put("countryList", countryList);
		return "getCountry";
	}
	
	public String getAirport() throws Exception {
		FlightService flightService = FlightServiceFactory.getFlightService();
		//Map parameters=ActionContext.getContext().getParameters();
		String country = ServletActionContext.getRequest().getParameter("country");
		List airportList = flightService.getAirportOfCountry(country);
		ActionContext.getContext().put("airportList", airportList);
		return "getAirport";
	}
	
	public String getTransAirport() throws Exception {
		String companyCode = ((String[])ActionContext.getContext().getParameters().get("company"))[0];
		FlightService flightService = FlightServiceFactory.getFlightService();
		CompanyTurncity companyTurncity = flightService.getTransAirportOfCompany(companyCode);
		if(companyTurncity != null) {
			ServletActionContext.getResponse().getWriter().write(companyTurncity.getTurnCityThreeCode().getAirportThreeCode());
		}
		return null;
	}
	
	public String getTransCompany() throws Exception {
		String companyCode = ((String[])ActionContext.getContext().getParameters().get("airport"))[0];
		FlightService flightService = FlightServiceFactory.getFlightService();
		CompanyTurncity companyTurncity = flightService.getCompanyOfTransAirport(companyCode);
		if(companyTurncity != null) {
			ServletActionContext.getResponse().getWriter().write(companyTurncity.getComTwoCode());
		}
		return null;
	} 
	
	public String query() throws Exception {
		FlightService flightService = FlightServiceFactory.getFlightService();
		boolean bQueryCityAirport = (queryCityAirport != null);
		Map<TwoCode, List[]> resultMap = null;
		if(bQueryCityAirport) {
			resultMap = flightService.getFullFlightList(departure, destination, itineryType, toDate, backDate, carrier, turncity);
		} else {
			resultMap = flightService.getFlightList(departure, destination, itineryType, toDate, backDate, carrier, turncity);
		}
		ActionContext.getContext().put("resultMap", resultMap);
		
		// put query condition
		ActionContext.getContext().put("toDate", toDate);
		ActionContext.getContext().put("backDate", backDate);
		ActionContext.getContext().put("carrier", carrier);
		ActionContext.getContext().put("turncity", turncity);
		ActionContext.getContext().put("passengersNum", passengersNum);
		ActionContext.getContext().put("bunk", bunk);
		return "queryResult";
	}
	
	public String getPrice() throws Exception {
		FlightService flightService = FlightServiceFactory.getFlightService();
		
		Map para = ActionContext.getContext().getParameters();
		String pNo = ((String[])para.get("passengersNum"))[0];
		String[] airCom = (String[])para.get("airCom");
		
		List<FlightWithPrice> result = new ArrayList<FlightWithPrice>();
		List<Map<String, String>> qteInput = new ArrayList<Map<String, String>>();
		airCom = MyUtils.removeDuplicatedElement(airCom);
		for(int i = 0; i < airCom.length; i ++) {
			String com = airCom[i];
			if(StringUtils.isBlank(com)) continue;
			
			FlightWithPrice flightWithPrice = new FlightWithPrice();
			//FlightInfo[] toFlight = new FlightInfo[]{};
			//FlightInfo[] backFlight = new FlightInfo[]{};
			List<FlightInfo> flightList = new ArrayList<FlightInfo>();

			String[] toback = new String[]{"to", "back"};
			
			Map<String, String> map = new HashMap<String, String>();
			map.put("carrier", com);
			String outwardPlane = "";
			String returnPlane = "";
			String cityPair = "";
			String outwardDate = "";
			String returnDate = "";
			String time = "";
			
			boolean bSel = false;
			for(int m = 0; m < toback.length; m ++) {
				String type = toback[m];
				String toSel = null;
				if(type.equals("to")) {
					toSel = (String[])para.get(com + "_radioBtnTo") == null ? null : ((String[])para.get(com + "_radioBtnTo"))[0];
				} else {
					toSel = (String[])para.get(com + "_radioBtnBack") == null ? null : ((String[])para.get(com + "_radioBtnBack"))[0];
				}
				if(toSel == null) continue;
				else bSel = true;
				for(int j = 0; j < 2; j ++) {
					String[] strplaneInfoId = ((String[])para.get(com + "_" + type + "_" + toSel + "_" + j + "_planeInfoId"));
					if(strplaneInfoId != null) {
						String planeInfoId = strplaneInfoId[0];
						PlaneInfo planeInfo = flightService.getPlaneInfo(planeInfoId);
						if(planeInfo != null) {
							String strTakeoffDate = ((String[])para.get(com + "_" + type + "_" + toSel + "_" + j + "_takeoffDate"))[0];
							String strPutdownDate = ((String[])para.get(com + "_" + type + "_" + toSel + "_" + j + "_putdownDate"))[0];
							Date takeoffDate = DateHelper.parseDate(strTakeoffDate);
							Date putdownDate = DateHelper.parseDate(strPutdownDate);
							String[] avaiableDaysArr = (String[])para.get(com + "_" + type + "_" + toSel + "_" + j + "_avaiableDay");
							boolean[] avaiableDays = new boolean[7];
							for(int k = 0; k < avaiableDaysArr.length; k ++) {
								int sel = Integer.parseInt(avaiableDaysArr[k]);
								avaiableDays[sel] = true;
							}
							FlightInfo flightInfo = new FlightInfo(planeInfo, avaiableDays, takeoffDate, putdownDate);
							
							if(type.equals("to")) {
								//toFlight = (FlightInfo[])ArrayUtils.add(toFlight, flightInfo);
								flightInfo.setType(FlightInfo.TYPE_TO);
							} else {
								//backFlight = (FlightInfo[])ArrayUtilsadd(backFlight, flightInfo);
								flightInfo.setType(FlightInfo.TYPE_BACK);
							}
							flightList.add(flightInfo);
							
							if(type.equals("to")) {
								if(j == 0) {
									outwardPlane += planeInfo.getPlaneno();
									cityPair += planeInfo.getDeparture().getAirportThreeCode() + "-" + planeInfo.getDestination().getAirportThreeCode();
									outwardDate += strTakeoffDate;
									time += planeInfo.getTakeofftime();
								}
								else if(j == 1) {
									outwardPlane += "-" + planeInfo.getPlaneno();
									cityPair += "-" + planeInfo.getDestination().getAirportThreeCode();
									outwardDate += "," + strTakeoffDate;
									
								}
							} else {
								// back
								if(j == 0) {
									returnPlane += planeInfo.getPlaneno();
									returnDate += strTakeoffDate;
									time += "," + planeInfo.getTakeofftime();
								}
								else if(j == 2) {
									returnPlane += "-" + planeInfo.getPlaneno();
									returnDate += "," + strTakeoffDate;
								}
							}
						}
					}
				}
			}
			
			if(!bSel) continue;
			
			map.put("outwardPlane", outwardPlane);
			map.put("returnPlane", returnPlane);
			map.put("cityPair", cityPair);
			map.put("outwardDate", outwardDate);
			map.put("returnDate", returnDate);
			map.put("time", time);
			map.put("passengerNo", pNo);
			//map.put("class", "A");
			
			qteInput.add(map);
			
			TwoCode company = flightService.getCompanyFromTwocode(com);
			flightWithPrice.setCompany(company);
			flightWithPrice.setFlightList(flightList);
			/*flightWithPrice.setToFlight(toFlight);
			if(backFlight.length != 0) {
				flightWithPrice.setBackFlight(backFlight);
			}*/
			
			
			// TODO: call QTE service to get price and tax
			//flightWithPrice.setPrice(1000);
			//flightWithPrice.setTax(100);
			
			result.add(flightWithPrice);
		}
		
		// debug the qte input
		debugQteMapList(qteInput);
		
		List<Map<String, String>> qteResult = executeQTE(qteInput);
		
		// debug the qte output
		debugQteMapList(qteResult);
		
		for(int i = 0; i < result.size(); i ++) {
			FlightWithPrice flightWithPrice = result.get(i);
			List<FlightInfo> flightList = flightWithPrice.getFlightList();
			FlightInfo[] toFlight = new FlightInfo[]{};
			FlightInfo[] backFlight = new FlightInfo[]{};
			for(int j = 0; j < flightList.size(); j ++) {
				FlightInfo flightInfo = flightList.get(j);
				String bunk = qteResult.get(i).get("bunk");
				flightInfo.setBunk(bunk);
				if(FlightInfo.TYPE_TO.equals(flightInfo.getType())) {
					toFlight = (FlightInfo[])ArrayUtils.add(toFlight, flightInfo);
				} else if(FlightInfo.TYPE_BACK.equals(flightInfo.getType())) {
					backFlight = (FlightInfo[])ArrayUtils.add(backFlight, flightInfo);
				}
			}
			flightWithPrice.setToFlight(toFlight);
			if(backFlight.length != 0) {
				flightWithPrice.setBackFlight(backFlight);
			}
			
			flightWithPrice.setPrice(Float.parseFloat(qteResult.get(i).get("price")));
			flightWithPrice.setTax(Float.parseFloat(qteResult.get(i).get("tax")));
		}
		
		ActionContext.getContext().put("flightPriceList", result);
		ActionContext.getContext().put("passengersNum", pNo);
		return "priceList";
	}
	
	private void debugQteMapList(List<Map<String, String>> mapList) {
		for(int i = 0; i < mapList.size(); i ++) {
			System.out.println("***** No " + (i+1) + " flight qte map list *****");
			Map<String, String> map = mapList.get(i);
			Iterator<Map.Entry<String, String>> iter = map.entrySet().iterator();
			while(iter.hasNext()) {
				Entry<String, String> entry = iter.next();
				String name = entry.getKey();
				String value = entry.getValue();
				System.out.println(name + " : " + value);
			}
		}
	}
	
	private List<Map<String, String>> executeQTE(List<Map<String, String>> input) {
		
		for(int i = 0; i < input.size(); i ++) {
			Map<String, String> map = input.get(i);
			// dummy data
			map.put("bunk", "Y");
			map.put("price", "1500");
			map.put("tax", "300");
		}
		return input;
		/*
		List<Map<String, String>> re = new ArrayList<Map<String, String>>();
		for(int i = 0; i < input.size(); i ++) {
			Map<String, String> map = input.get(i);
			String carrier = map.get("carrier");
			Processor p = ProcessorFactory.getProcessor(carrier);
			List list = new ArrayList();
			list.add(map);
			list = p.excuteQTE(list);
			re.add((Map<String, String>)list.get(0));
			
		}
		return re;*/
	}
	
	public String queryThreecode() {
		String query = MyUtils.getUrlDecodedRequestParameter(ServletActionContext.getRequest(), "query", "utf-8");
		if(!StringUtils.isBlank(query)) {
			FlightService flightService = FlightServiceFactory.getFlightService();
			List list = flightService.queryThreecodeByStart(query.trim().toUpperCase());
			ActionContext.getContext().put("threecodeList", list);
		}
		return "threecodeQueryResult";
	}

	public String getBackDate() {
		return backDate;
	}

	public void setBackDate(String backDate) {
		this.backDate = backDate;
	}

	public String getBunk() {
		return bunk;
	}

	public void setBunk(String bunk) {
		this.bunk = bunk;
	}

	public String getCarrier() {
		return carrier;
	}

	public void setCarrier(String carrier) {
		this.carrier = carrier;
	}

	public String getDeparture() {
		return departure;
	}

	public void setDeparture(String departure) {
		this.departure = departure;
	}

	public String getDestination() {
		return destination;
	}

	public void setDestination(String destination) {
		this.destination = destination;
	}

	public String getToDate() {
		return toDate;
	}

	public void setToDate(String toDate) {
		this.toDate = toDate;
	}

	public String getTurncity() {
		return turncity;
	}

	public void setTurncity(String turncity) {
		this.turncity = turncity;
	}

	public String getItineryType() {
		return itineryType;
	}

	public void setItineryType(String itineryType) {
		this.itineryType = itineryType;
	}

	public String getPassengersNum() {
		return passengersNum;
	}

	public void setPassengersNum(String passengersNum) {
		this.passengersNum = passengersNum;
	}

	public String getQueryCityAirport() {
		return queryCityAirport;
	}

	public void setQueryCityAirport(String queryCityAirport) {
		this.queryCityAirport = queryCityAirport;
	}
	
}
